package com.hao.utils;

import com.hao.entity.PoiModel;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @description: Excel合并值相同单元格工具类
 * @author: haohj
 * @create: 2019-07-24 11:03
 **/
public class ExcelMergeCellUtils {
    private final static String excel2003L = ".xls";    //2003- 版本的excel
    private final static String excel2007U = ".xlsx";   //2007+ 版本的excel
    private static FormulaEvaluator evaluator;

    /**
     * @param mergeIndex 合并单元格的列
     */
    public static void mergeCell(Workbook workbook, int sheetIndex, int startRowIndex, int[] mergeIndex) {
        List<PoiModel> poiModels = new ArrayList<>();
        Sheet sheet = workbook.getSheetAt(sheetIndex);
        for (int index = startRowIndex; index < sheet.getLastRowNum(); index++) {
            Row row = sheet.getRow(index);
            for (int i = 0; i < sheet.getRow(startRowIndex).getLastCellNum(); i++) {
                String old = "";
                /*old存的是上一行统一位置的单元的值，第一行是最上一行了，所以从第二行开始记*/
                if (index > startRowIndex) {
                    old = poiModels.get(i) == null ? "" : poiModels.get(i).getContent();
                }
                for (int j = 0; j < mergeIndex.length; j++) {
                    //处理起始行
                    if (index == startRowIndex) {
                        /*记录第一行的开始行和开始列*/
                        PoiModel poiModel = new PoiModel();

                        poiModel.setOldContent(getCellValueByCell(row.getCell(i)));
                        poiModel.setContent(getCellValueByCell(row.getCell(i)));
                        poiModel.setRowIndex(startRowIndex);
                        poiModel.setCellIndex(i);
                        poiModels.add(poiModel);
                        break;
                    } else if (i > 0 && mergeIndex[j] == i) {
                        /*这边i>0也是因为第一列已经是最前一列了，只能从第二列开始*/
                        /*当前同一列的内容与上一行同一列不同时，把那以上的合并, 或者在当前元素一样的情况下，前一列的元素并不一样，这种情况也合并*/
                        /*如果不需要考虑当前行与上一行内容相同，但是它们的前一列内容不一样则不合并的情况，把下面条件中||poiModels.get(i).getContent().equals(getCellValueByCell(row.getCell(i))) && !poiModels.get(i - 1).getOldContent().equals(map.get(title[i-1]))去掉就行*/
                        if (!poiModels.get(i).getContent().equals(getCellValueByCell(row.getCell(i))) || poiModels.get(i).getContent().equals(getCellValueByCell(row.getCell(i))) && !poiModels.get(i - 1).getOldContent().equals(getCellValueByCell(row.getCell(i - 1)))) {
                            /*当前行的当前列与上一行的当前列的内容不一致时，则把当前行以上的合并*/
                            CellRangeAddress cra = new CellRangeAddress(poiModels.get(i).getRowIndex()/*从第二行开始*/, index - 1/*到第几行*/, poiModels.get(i).getCellIndex()/*从某一列开始*/, poiModels.get(i).getCellIndex()/*到第几列*/);
                            //在sheet里增加合并单元格
                            sheet.addMergedRegion(cra);
                            /*重新记录该列的内容为当前内容，行标记改为当前行标记，列标记则为当前列*/
                            poiModels.get(i).setContent(getCellValueByCell(row.getCell(i)));
                            poiModels.get(i).setRowIndex(index);
                            poiModels.get(i).setCellIndex(i);
                        }
                    }

                    /*处理第一列的情况*/
                    if (mergeIndex[j] == i && i == 0 && !poiModels.get(i).getContent().equals(getCellValueByCell(row.getCell(i)))) {
                        /*当前行的当前列与上一行的当前列的内容不一致时，则把当前行以上的合并*/
                        CellRangeAddress cra = new CellRangeAddress(poiModels.get(i).getRowIndex()/*从第二行开始*/, index - 1/*到第几行*/, poiModels.get(i).getCellIndex()/*从某一列开始*/, poiModels.get(i).getCellIndex()/*到第几列*/);
                        //在sheet里增加合并单元格
                        sheet.addMergedRegion(cra);
                        /*重新记录该列的内容为当前内容，行标记改为当前行标记*/
                        poiModels.get(i).setContent(getCellValueByCell(row.getCell(i)));
                        poiModels.get(i).setRowIndex(index);
                        poiModels.get(i).setCellIndex(i);
                    }

                    /*最后一行没有后续的行与之比较，所有当到最后一行时则直接合并对应列的相同内容*/
                    if (mergeIndex[j] == i && (index == sheet.getLastRowNum() - 1)) {
                        CellRangeAddress cra = new CellRangeAddress(poiModels.get(i).getRowIndex()/*从第二行开始*/, sheet.getLastRowNum()/*到第几行*/, poiModels.get(i).getCellIndex()/*从某一列开始*/, poiModels.get(i).getCellIndex()/*到第几列*/);
                        //在sheet里增加合并单元格
                        sheet.addMergedRegion(cra);
                    }
                }
                /*在每一个单元格处理完成后，把这个单元格内容设置为old内容*/
                poiModels.get(i).setOldContent(old);
            }
        }
    }

    /**
     * 描述：根据文件后缀，自适应上传文件的版本
     */
    public static Workbook getWorkbook(InputStream inStr, String fileName) throws Exception {
        Workbook wb = null;
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        if (excel2003L.equals(fileType)) {
            wb = new HSSFWorkbook(inStr);  //2003-
        } else if (excel2007U.equals(fileType)) {
            wb = new XSSFWorkbook(inStr);  //2007+
        } else {
            throw new Exception("解析的文件格式有误！");
        }
        return wb;
    }

    //获取单元格各类型值，返回字符串类型
    private static String getCellValueByCell(Cell cell) {
        //判断是否为null或空串
        if (cell == null || cell.toString().trim().equals("")) {
            return "";
        }
        String cellValue = "";
        int cellType = cell.getCellType();
        if (cellType == Cell.CELL_TYPE_FORMULA) { //表达式类型
            cellType = evaluator.evaluate(cell).getCellType();
        }

        switch (cellType) {
            case Cell.CELL_TYPE_STRING: //字符串类型
                cellValue = cell.getStringCellValue().trim();
                cellValue = StringUtils.isEmpty(cellValue) ? "" : cellValue;
                break;
            case Cell.CELL_TYPE_BOOLEAN:  //布尔类型
                cellValue = String.valueOf(cell.getBooleanCellValue());
                break;
            case Cell.CELL_TYPE_NUMERIC: //数值类型
                if (HSSFDateUtil.isCellDateFormatted(cell)) {  //判断日期类型
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); //使用了默认的格式创建了一个日期格式化对象。
                    cellValue = dateFormat.format(cell.getDateCellValue()); //可以把日期转换转指定格式的字符串
                } else {  //否
                    cellValue = new DecimalFormat("#.######").format(cell.getNumericCellValue());
                }
                break;
            default: //其它类型，取空串吧
                cellValue = "";
                break;
        }
        return cellValue;
    }
}
